﻿using System;
using System.Collections.Generic;
using System.Data;
using System.Linq;
using System.Text;
using Tilver.Coder.CommandExcuteResult;
using Tilver.Coder.Core;
using Tilver.Coder.Utility;

namespace Tilver.Coder.Engine
{
    internal class CommandPOEngine : MOEngine<CoderCommand>, ICommandEngine
    {
        public CoderCommand Command
        {
            get { return MO; }
            set { MO = value; }
        }

        protected override void ResponseClass(StringBuilder response, int tabs)
        {
            //begin
            response.AppendLine(ExtensionUtil.GetCoderSummary(tabs, MO.Description, string.Format("{0}({1})", MO.FullName, "逻辑类")));
            response.AppendFormatLine(tabs, "public class {0} : DbManagerBase", MO.CodeName.ToCoderPOClassName());
            response.AppendTabLine(tabs, "{");
            //输出字段
            ResponseFields(response, tabs + 1);
            response.AppendLine();
            //输出属性
            ResponseProperties(response, tabs + 1);
            response.AppendLine();
            //输出构造函数
            ResponseCtors(response, tabs + 1);
            response.AppendLine();
            //输出私有方法
            ResponsePrivate(response, tabs + 1);
            response.AppendLine();
            //输出设置参数值方法
            ResponseSetFunctions(response, tabs + 1);
            response.AppendLine();
            //输出获取参数值方法
            ResponseGetFunctions(response, tabs + 1);
            response.AppendLine();
            //输出返回参数
            ResponseReturnFunctions(response, tabs + 1);
            response.AppendLine();
            //输出存储近程返回结果
            ResponseResultFunction(response, tabs + 1);
            //end
            response.AppendTabLine(tabs, "}");
        }

        protected override void ResponseCtors(StringBuilder response, int tabs)
        {
            var poClassName = MO.CodeName.ToCoderPOClassName();
            var eoClassName = MO.CodeName.ToCoderEOClassName();

            //response.AppendLine(ExtensionUtil.GetCoderSummary(tabs, "构造函数"));
            //response.AppendFormatLine(tabs, "public {0}() : base(typeof({1}),null) {{ }}", poClassName, eoClassName);
            //response.AppendLine();

            response.AppendLine(ExtensionUtil.GetCoderSummary(tabs, "构造函数"));
            response.AppendLine(ExtensionUtil.GetCoderParamSummary(tabs, "routeData", "路由数据"));
            //response.AppendFormatLine(tabs, "public {0}(object routeData = null) : base(typeof({1}), routeData) {{ }}", poClassName, eoClassName);
            response.AppendFormatLine(tabs, "public {0}(object routeData = null) : base(routeData) {{ }}", poClassName);
            response.AppendLine();

            response.AppendLine(ExtensionUtil.GetCoderSummary(tabs, "构造函数"));
            response.AppendLine(ExtensionUtil.GetCoderParamSummary(tabs, "connectionStringName", "连接字符串名称"));
            response.AppendFormatLine(tabs, "public {0}(string connectionStringName) : base(connectionStringName) {{ }}", poClassName);
            response.AppendLine();
        }

        private void ResponseFields(StringBuilder response, int tabs)
        {
            response.AppendFormatLine(tabs, "private const string _procName = \"{0}\";", DBTextStyle.GetCommandFullName(MO.Owner, MO.Name));
            //response.AppendTabLine(tabs, "private ProcDao _dao;");
            //response.AppendTabLine(tabs, "private static DbParameter[] _paras;");
            //response.AppendTabLine(tabs, "private static object _lock = new object();");
        }
        private void ResponsePrivate(StringBuilder response, int tabs)
        {

            response.AppendLine(ExtensionUtil.GetCoderSummary(tabs, "存储过程操作对象"));
            response.AppendLine(ExtensionUtil.GetCoderReturnSummary(tabs, ""));
            response.AppendTabLine(tabs, "private DbAdoBase AdoBase()");
            response.AppendTabLine(tabs, "{");
            //response.AppendTabLine(tabs + 1, "return new DbAdoBase(_procName, CommandType.StoredProcedure, DataBase);");
            response.AppendTabLine(tabs + 1, "return DataBase.CreateDbAdo(_procName, CommandType.StoredProcedure);");
            response.AppendTabLine(tabs, "}");

        }
        private void ResponseProperties(StringBuilder response, int tabs)
        {
            response.AppendLine(ExtensionUtil.GetCoderSummary(tabs, "存储过程名称"));
            response.AppendTabLine(tabs, "public string ProcName");
            response.AppendTabLine(tabs, "{");
            response.AppendTabLine(tabs + 1, "get { return _procName; }");
            response.AppendTabLine(tabs, "}");

            //response.AppendTabLine(tabs, "protected ProcDao Dao");
            //response.AppendTabLine(tabs, "{");
            //response.AppendTabLine(tabs + 1, "get");
            //response.AppendTabLine(tabs + 1, "{");
            //response.AppendTabLine(tabs + 2, "if (_dao == null)");
            //response.AppendTabLine(tabs + 2, "{");

            //response.AppendFormatLine(tabs + 3, "_dao = Database.CreateProcDao(\"{0}\");", MO.FullName);
            //response.AppendTabLine(tabs + 3, "DbParameter[] paras = GetParameters(Database);");
            //response.AppendLine();
            //response.AppendTabLine(tabs + 3, "for (int i = 0; i < paras.Length; i++)");
            //response.AppendTabLine(tabs + 3, "{");
            //response.AppendTabLine(tabs + 4, "DbParameter para = (DbParameter)((ICloneable)paras[i]).Clone();");
            //response.AppendTabLine(tabs + 4, "_dao.AddParameter(para);");
            //response.AppendTabLine(tabs + 3, "}");
            //response.AppendTabLine(tabs + 2, "}");
            //response.AppendTabLine(tabs + 2, "return _dao;");
            //response.AppendTabLine(tabs + 1, "}");
            //response.AppendTabLine(tabs, "}");

            //response.AppendTabLine(tabs, "private static DbParameter[] GetParameters(Database db)");
            //response.AppendTabLine(tabs, "{");
            //response.AppendTabLine(tabs + 1, "if (_paras == null)");
            //response.AppendTabLine(tabs + 1, "{");
            //response.AppendTabLine(tabs + 2, "lock (_lock)");
            //response.AppendTabLine(tabs + 2, "{");
            //response.AppendTabLine(tabs + 3, "if (_paras == null)");
            //response.AppendTabLine(tabs + 3, "{");
            //response.AppendTabLine(tabs + 4, "_paras = new DbParameter[]");
            //response.AppendTabLine(tabs + 4, "{");

            //foreach (var parameter in MO.Parameters)
            //{
            //    response.AppendFormatLine(tabs + 5,
            //        "db.CreateParameter(\"{0}\", DbType.{1}, {2}, ParameterDirection.{3}) ,",
            //        parameter.Name,
            //        parameter.DbType,
            //        parameter.Size,
            //        parameter.Direction);
            //}
            //response.AppendTabLine(tabs + 4, "};");
            //response.AppendTabLine(tabs + 3, "}");
            //response.AppendTabLine(tabs + 2, "}");
            //response.AppendTabLine(tabs + 1, "}");
            //response.AppendTabLine(tabs + 1, "return _paras;");
            //response.AppendTabLine(tabs, "}");
        }

        private void ResponseSetFunctions(StringBuilder response, int tabs)
        {
            //foreach (var parameter in MO.InputParameters)
            //{
            //    string propertyName = parameter.CodeName.ToCoderPropertyName();
            //    string paraName = parameter.CodeName.ToCoderParameterName();

            //    response.AppendLine(ExtensionUtil.GetCoderSummary(tabs, "设置参数值"));
            //    response.AppendLine(ExtensionUtil.GetCoderParamSummary(tabs, paraName, parameter.Description));
            //    response.AppendFormatLine(tabs, "public void Set{0}({1} {2})", propertyName, parameter.CSharpType, paraName);
            //    response.AppendTabLine(tabs, "{");
            //    response.AppendFormatLine(tabs + 1, "AdoBase.SetParameterValue(\"{0}\", {1});", parameter.Name, TableMOEngine.GetColumnParaValueString(paraName, parameter));
            //    response.AppendTabLine(tabs, "}");
            //    response.AppendLine();
            //}
        }

        private void ResponseGetFunctions(StringBuilder response, int tabs)
        {
            foreach (var parameter in MO.OutputParameters)
            {
                var fieldName = parameter.CodeName.ToCoderFieldName();
                var propertyName = parameter.CodeName.ToCoderPropertyName();
                response.AppendFormatLine(tabs, "private {0} {1};", parameter.CSharpType, fieldName);
                response.AppendLine(ExtensionUtil.GetCoderSummary(tabs, parameter.Description));
                response.AppendLine(ExtensionUtil.GetCoderReturnSummary(tabs, string.Empty));
                response.AppendFormatLine(tabs, "public {0} Get{1}()", parameter.CSharpType, propertyName);
                response.AppendTabLine(tabs, "{");
                response.AppendFormatLine(tabs + 1, "return {0};", fieldName);
                //response.AppendFormatLine(tabs + 1, "object value = AdoBase().Command.GetParameterValue(\"{0}\");", parameter.Name);
                //response.AppendLine();

                //if (parameter.AllowDBNull)
                //    response.AppendFormatLine(tabs + 1, "return (value is DBNull) ? null : ({0})value;", parameter.CSharpType);
                //else
                //    response.AppendFormatLine(tabs + 1, "return ({0})value;", parameter.CSharpType);
                response.AppendTabLine(tabs, "}");
                response.AppendLine();
            }
        }

        private void ResponseReturnFunctions(StringBuilder response, int tabs)
        {
            //response.AppendLine(ExtensionUtil.GetCoderSummary(tabs, "获取返回值DbParameter参数的值"));
            //response.AppendLine(ExtensionUtil.GetCoderReturnSummary(tabs, string.Empty));
            //response.AppendTabLine(tabs, "public object GetReturnValue()");
            //response.AppendTabLine(tabs, "{");
            //response.AppendTabLine(tabs + 1, "return Dao.GetReturnValue();");
            //response.AppendTabLine(tabs, "}");
        }

        private void ResponseResultFunction(StringBuilder response, int tabs)
        {
            switch (MO.CommandResult.CommandResult)
            {
                case ExecuteResultEnum.ExecuteNonQuery:
                    ResponseExecuteNonQuery(response, tabs);
                    //new CommandExecuteResultEngine().ResponseExecuteNonQuery(response, tabs, MO);
                    break;
                case ExecuteResultEnum.ExecuteScalar:
                    ResponseExecuteScalar(response, tabs);
                    //new CommandExecuteResultEngine().ResponseExecuteScalar(response, tabs, MO);
                    break;
                case ExecuteResultEnum.ExecuteSingle:
                    ResponseExecuteSingle(response, tabs);
                    //new CommandExecuteResultEngine().ResponseExecuteSingle(response, tabs, MO);
                    break;
                case ExecuteResultEnum.ExecuteReader:
                    ResponseExecuteReader(response, tabs);
                    //new CommandExecuteResultEngine().ResponseExecuteReader(response, tabs, MO);
                    break;
                default:
                    throw new NotImplementedException();
            }
        }

        #region 存储过程返回结果

        private void ResponseExecuteNonQuery(StringBuilder response, int tabs)
        {
            response.AppendLine(ExtensionUtil.GetCoderSummary(tabs, "执行存储过程并返回受影响的行数"));
            response.AppendLine(ExtensionUtil.GetDataObjectsInfo(tabs, MO.Parameters, ExtensionUtil.IndexType.ParamSummary));
            response.AppendLine(ExtensionUtil.GetCoderTMSummary(tabs));
            response.AppendLine(ExtensionUtil.GetCoderReturnSummary(tabs, string.Empty));
            response.AppendFormatLine(tabs, "public int ExecuteNonQuery({0}, TransactionManager tm = null)",
                ExtensionUtil.GetDataObjectsInfo(tabs, MO.Parameters.Where(w => w.Direction != ParameterDirection.ReturnValue), ExtensionUtil.IndexType.ParamList));
            response.AppendTabLine(tabs, "{");
            response.AppendTabLine(tabs + 1, "var adoBase = AdoBase();");
            response.AppendTabLine(tabs + 1, "var ret = adoBase");
            foreach (var para in MO.Parameters.Where(w => w.Direction != ParameterDirection.ReturnValue))
            {
                var sqlParamName = DBTextStyle.GetParameterName(para.Name);
                var addParameterStr = "AddInParameter";
                if (para.Direction == ParameterDirection.Input)
                    addParameterStr = "AddInParameter";
                if (para.Direction == ParameterDirection.Output)
                    addParameterStr = "AddOutParameter";
                if (para.Direction == ParameterDirection.InputOutput)
                    addParameterStr = "AddInOutParameter";
                response.AppendFormatLine(tabs + 2, ".{4}(\"{0}\", {1}, DbType.{2}, {3})",
                                                sqlParamName,
                                                para.CodeName.ToCoderParameterName(),
                                                para.DbType,
                                                para.Size, addParameterStr);
            }
            response.AppendTabLine(tabs + 2, ".ExecuteNonQuery(tm);");
            foreach (var parameter in MO.OutputParameters)
            {

                var fieldName = parameter.CodeName.ToCoderFieldName();
                var sqlParamName = DBTextStyle.GetParameterName(parameter.Name);
                response.AppendTabLine(tabs + 1, "{");
                response.AppendFormatLine(tabs + 2, "var value = adoBase.Command.Parameters[\"{0}\"].Value;", sqlParamName);
                response.AppendFormatLine(tabs + 2, "{0} = (value is DBNull) ? null : ({1})value;", fieldName, parameter.CSharpType);
                response.AppendTabLine(tabs + 1, "}");

            }
            response.AppendTabLine(tabs + 1, "return ret;");
            response.AppendTabLine(tabs, "}");
            response.AppendLine();
            //response.AppendTabLine(tabs, "public int ExecuteNonQuery()");
            //response.AppendTabLine(tabs, "{");
            //response.AppendTabLine(tabs + 1, "return ExecuteNonQuery(null);");
            //response.AppendTabLine(tabs, "}");
            //response.AppendLine();
            //response.AppendLine(ExtensionUtil.GetCoderSummary(tabs, "执行SQL语句并返回受影响的行数"));
            //response.AppendLine(ExtensionUtil.GetCoderTMSummary(tabs));
            //response.AppendLine(ExtensionUtil.GetCoderReturnSummary(tabs, string.Empty));
            //response.AppendTabLine(tabs, "public int ExecuteNonQuery(TransactionManager tm)");
            //response.AppendTabLine(tabs, "{");
            //response.AppendTabLine(tabs + 1, "return Dao.ExecuteNonQuery(tm);");
            //response.AppendTabLine(tabs, "}");
        }

        private void ResponseExecuteScalar(StringBuilder response, int tabs)
        {
            if (MO.CommandResult.CommandResult != ExecuteResultEnum.ExecuteScalar)
                throw new NotImplementedException();
            var scalar = MO.CommandResult as ExecuteScalarResult;
            //response.AppendLine(ExtensionUtil.GetCoderSummary(tabs, "执行查询语句并返回首行首列数据"));
            //response.AppendLine(ExtensionUtil.GetCoderReturnSummary(tabs, string.Empty));
            //response.AppendFormatLine(tabs, "public {0} ExecuteScalar()", scalar.CSharpType);
            //response.AppendTabLine(tabs, "{");
            //response.AppendTabLine(tabs + 1, "return ExecuteScalar(null);");
            //response.AppendTabLine(tabs, "}");
            //response.AppendLine();
            //response.AppendLine(ExtensionUtil.GetCoderSummary(tabs, "执行查询语句并返回首行首列数据"));
            //response.AppendLine(ExtensionUtil.GetCoderTMSummary(tabs));
            //response.AppendLine(ExtensionUtil.GetCoderReturnSummary(tabs, string.Empty));
            //response.AppendFormatLine(tabs, "public {0} ExecuteScalar(TransactionManager tm)", scalar.CSharpType);
            //response.AppendTabLine(tabs, "{");
            //response.AppendTabLine(tabs + 1, "object value =  Dao.ExecuteScalar(tm);");
            //response.AppendFormatLine(tabs + 1, " return value == null ? null : ({0})value;", scalar.CSharpType);
            //response.AppendTabLine(tabs, "}");
            //response.AppendLine();
            response.AppendLine(ExtensionUtil.GetCoderSummary(tabs, "执行存储过程并返回受影响的行数"));
            response.AppendLine(ExtensionUtil.GetDataObjectsInfo(tabs, MO.Parameters, ExtensionUtil.IndexType.ParamSummary));
            response.AppendLine(ExtensionUtil.GetCoderTMSummary(tabs));
            response.AppendLine(ExtensionUtil.GetCoderReturnSummary(tabs, string.Empty));
            response.AppendFormatLine(tabs, "public {0} ExecuteScalar({1}, TransactionManager tm = null)",
                scalar.CSharpType,
                ExtensionUtil.GetDataObjectsInfo(tabs, MO.Parameters.Where(w => w.Direction != ParameterDirection.ReturnValue), ExtensionUtil.IndexType.ParamList));
            response.AppendTabLine(tabs, "{");
            response.AppendTabLine(tabs + 1, "var adoBase = AdoBase();");
            response.AppendTabLine(tabs + 1, "var ret = adoBase");
            foreach (var para in MO.Parameters.Where(w => w.Direction != ParameterDirection.ReturnValue))
            {
                string sqlParamName = DBTextStyle.GetParameterName(para.Name);
                var addParameterStr = "AddInParameter";
                if (para.Direction == ParameterDirection.Input)
                    addParameterStr = "AddInParameter";
                if (para.Direction == ParameterDirection.Output)
                    addParameterStr = "AddOutParameter";
                if (para.Direction == ParameterDirection.InputOutput)
                    addParameterStr = "AddInOutParameter";
                response.AppendFormatLine(tabs + 2, ".{4}(\"{0}\", {1}, DbType.{2}, {3})",
                                                sqlParamName,
                                                para.CodeName.ToCoderParameterName(),
                                                para.DbType,
                                                para.Size, addParameterStr);
            }
            response.AppendTabLine(tabs + 2, ".ExecuteScalar(tm);");
            foreach (var parameter in MO.OutputParameters)
            {

                var fieldName = parameter.CodeName.ToCoderFieldName();
                var sqlParamName = DBTextStyle.GetParameterName(parameter.Name);
                response.AppendTabLine(tabs + 1, "{");
                response.AppendFormatLine(tabs + 2, "var value = adoBase.Command.Parameters[\"{0}\"].Value;", sqlParamName);
                response.AppendFormatLine(tabs + 2, "{0} = (value is DBNull) ? null : ({1})value;", fieldName, parameter.CSharpType);
                response.AppendTabLine(tabs + 1, "}");

            }
            response.AppendFormatLine(tabs + 1, "return ret == null ? null : ({0})ret;", scalar.CSharpType);
            response.AppendTabLine(tabs, "}");
            response.AppendLine();
        }

        private void ResponseExecuteSingle(StringBuilder response, int tabs)
        {
            response.AppendLine(ExtensionUtil.GetCoderSummary(tabs, "执行存储过程并返回受影响的行数"));
            response.AppendLine(ExtensionUtil.GetDataObjectsInfo(tabs, MO.Parameters.Where(w => w.Direction != ParameterDirection.ReturnValue), ExtensionUtil.IndexType.ParamSummary));
            response.AppendLine(ExtensionUtil.GetCoderTMSummary(tabs));
            response.AppendLine(ExtensionUtil.GetCoderReturnSummary(tabs, string.Empty));
            response.AppendFormatLine(tabs, "public {0} ExecSingle({1}, TransactionManager tm = null)",
                MO.EOName,
                ExtensionUtil.GetDataObjectsInfo(tabs, MO.Parameters.Where(w => w.Direction != ParameterDirection.ReturnValue), ExtensionUtil.IndexType.ParamList));
            response.AppendTabLine(tabs, "{");
            response.AppendTabLine(tabs + 1, "var adoBase = AdoBase();");
            response.AppendTabLine(tabs + 1, "var ret = adoBase");
            foreach (var para in MO.Parameters.Where(w => w.Direction != ParameterDirection.ReturnValue))
            {
                string sqlParamName = DBTextStyle.GetParameterName(para.Name);
                var addParameterStr = "AddInParameter";
                if (para.Direction == ParameterDirection.Input)
                    addParameterStr = "AddInParameter";
                if (para.Direction == ParameterDirection.Output)
                    addParameterStr = "AddOutParameter";
                if (para.Direction == ParameterDirection.InputOutput)
                    addParameterStr = "AddInOutParameter";
                response.AppendFormatLine(tabs + 2, ".{4}(\"{0}\", {1}, DbType.{2}, {3})",
                                                sqlParamName,
                                                para.CodeName.ToCoderParameterName(),
                                                para.DbType,
                                                para.Size, addParameterStr);
            }
            response.AppendFormatLine(tabs, ".ExecuteSingle(new {0}().GetMapper(), tm);", MO.EOName);
            foreach (var parameter in MO.OutputParameters)
            {

                var fieldName = parameter.CodeName.ToCoderFieldName();
                var sqlParamName = DBTextStyle.GetParameterName(parameter.Name);
                response.AppendTabLine(tabs + 1, "{");
                response.AppendFormatLine(tabs + 2, "var value = adoBase.Command.Parameters[\"{0}\"].Value;", sqlParamName);
                response.AppendFormatLine(tabs + 2, "{0} = (value is DBNull) ? null : ({1})value;", fieldName, parameter.CSharpType);
                response.AppendTabLine(tabs + 1, "}");

            }
            response.AppendTabLine(tabs + 1, "return ret;");
            response.AppendTabLine(tabs, "}");
            response.AppendLine();
        }

        private void ResponseExecuteReader(StringBuilder response, int tabs)
        {
            response.AppendLine(ExtensionUtil.GetCoderSummary(tabs, "执行存储过程并返回受影响的行数"));
            response.AppendLine(ExtensionUtil.GetDataObjectsInfo(tabs, MO.Parameters.Where(w => w.Direction != ParameterDirection.ReturnValue), ExtensionUtil.IndexType.ParamSummary));
            response.AppendLine(ExtensionUtil.GetCoderTMSummary(tabs));
            response.AppendLine(ExtensionUtil.GetCoderReturnSummary(tabs, string.Empty));
            //response.AppendFormatLine(tabs, "public IEnumerable<{0}> ExecList({1}, TransactionManager tm = null)",
            response.AppendFormatLine(tabs, "public List<{0}> ExecList({1}, TransactionManager tm = null)",
                MO.EOName,
                ExtensionUtil.GetDataObjectsInfo(tabs, MO.Parameters.Where(w => w.Direction != ParameterDirection.ReturnValue), ExtensionUtil.IndexType.ParamList));
            response.AppendTabLine(tabs, "{");
            response.AppendTabLine(tabs + 1, "var adoBase = AdoBase();");
            response.AppendTabLine(tabs + 1, "var ret = adoBase");
            foreach (var para in MO.Parameters.Where(w => w.Direction != ParameterDirection.ReturnValue))
            {
                var sqlParamName = DBTextStyle.GetParameterName(para.Name);
                var addParameterStr = "AddInParameter";
                if (para.Direction == ParameterDirection.Input)
                    addParameterStr = "AddInParameter";
                if (para.Direction == ParameterDirection.Output)
                    addParameterStr = "AddOutParameter";
                if (para.Direction == ParameterDirection.InputOutput)
                    addParameterStr = "AddInOutParameter";
                response.AppendFormatLine(tabs + 2, ".{4}(\"{0}\", {1}, DbType.{2}, {3})",
                                             sqlParamName,
                                             para.CodeName.ToCoderParameterName(),
                                             para.DbType,
                                             para.Size,
                                             addParameterStr);
            }
            response.AppendFormatLine(tabs + 2, ".ExecuteList(new {0}().GetMapper(), tm);", MO.EOName);
            foreach (var parameter in MO.OutputParameters)
            {

                var fieldName = parameter.CodeName.ToCoderFieldName();
                var sqlParamName = DBTextStyle.GetParameterName(parameter.Name);
                response.AppendTabLine(tabs + 1, "{");
                response.AppendFormatLine(tabs + 2, "var value = adoBase.Command.Parameters[\"{0}\"].Value;", sqlParamName);
                response.AppendFormatLine(tabs + 2, "{0} = (value is DBNull) ? null : ({1})value;", fieldName, parameter.CSharpType);
                response.AppendTabLine(tabs + 1, "}");

            }
            response.AppendTabLine(tabs + 1, "return ret;");
            response.AppendTabLine(tabs, "}");
            response.AppendLine();
        }
        #endregion
    }
}
